package com.woniuxy.aspect;

import com.woniuxy.pojo.SysLogOpt;
import com.woniuxy.pojo.SysRole;
import com.woniuxy.pojo.SysRoleUser;
import com.woniuxy.pojo.User;
import com.woniuxy.config.RabbitConfig;

import com.woniuxy.interfaces.Log;
import com.woniuxy.service.SysLogOptService;
import com.woniuxy.service.SysRoleService;
import com.woniuxy.service.SysRoleUserService;
import com.woniuxy.service.UserService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;

/**
* 日志记录AOP切面
* */
@Aspect
@Component
public class LogAspect {
    @Autowired
    private SysLogOptService sysLogOptService;

    @Autowired
    private UserService userService;
    @Autowired
    private SysRoleUserService sysRoleUserService;

    @Autowired
    private RedisTemplate<String, SysLogOpt> redisTemplate;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    private static final String LOG_LIST_KEY = "log:list";



    /**
     * 定义切点，匹配所有的带有@Log注解的方法
     */
    @Pointcut("@annotation(com.woniuxy.interfaces.Log)")
    public void logPointcut(){}

    /**
     * 在目标方法执行之前执行获取从前端获取到的标题和用户id，
     */
    @Around("logPointcut() && @annotation(log)")
    public Object Around(ProceedingJoinPoint joinPoint, Log log) throws Throwable {

        //构建日志对象
        SysLogOpt sysLogOpt = new SysLogOpt();//保存日志的实体

        // 获取当前请求对象
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attrs == null) {
//            log.warn("当前无请求上下文，跳过日志记录");
            return null;
        }

        //通过request获取到从前端传递过来的按钮标题，和用户id
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                                                                    .getRequestAttributes())
                                                                    .getRequest();

        //解码请求头
        String buttonTitle = URLDecoder.decode(request.getHeader("X-Button-Title"), StandardCharsets.UTF_8);
        String userId = URLDecoder.decode(request.getHeader("X-User-Id"), StandardCharsets.UTF_8);

//        根据userId去数据库中查询用户信息
        User user = userService.getById(userId);
        //根据用户的id去用户角色表中查询用户角色
        SysRoleUser roleUser = sysRoleUserService.getById(userId);
        //根据角色id查询角色信息
        SysRole role = sysRoleService.getById(roleUser.getRoleId());

        //获取ipd地址
        String ipAddress = request.getRemoteAddr();



        //获取全类名
        String fullClass = joinPoint.getSignature().getDeclaringTypeName();
        //获取方法的消息
        String methodName = joinPoint.getSignature().getName();
        //获取方法的参数
        String params = Arrays.toString(joinPoint.getArgs());

        Object result = null;
        String respData = null;
        String exceptionMessage = null;


        try {
            //执行目标方法

            result = joinPoint.proceed();
            respData = result != null ? result.toString() : null;
        } catch (Throwable  e) {
            exceptionMessage = e.getMessage();  // 记录异常信息
            respData = "Exception: " + exceptionMessage;
            throw e; // 继续抛出异常
        } finally {


            sysLogOpt.setUId(user.getId());
            sysLogOpt.setUName(user.getUsername());
            sysLogOpt.setOptName(buttonTitle);
            sysLogOpt.setReqType(request.getMethod());
            sysLogOpt.setReqUrl(request.getRequestURI());
            sysLogOpt.setFullClass(fullClass);
            sysLogOpt.setMethod(methodName);
            sysLogOpt.setReqParams(params);
            sysLogOpt.setRespData(respData);
            sysLogOpt.setOptTime(new Date());

            sysLogOpt.setURole(role.getRoleName());
            sysLogOpt.setIpaddress(ipAddress);


            // mq异步写入 Redis 缓存 List
            rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME,RabbitConfig.ROUTING_KEY_CACHE,sysLogOpt);
        }
        return result;

    }
}
